/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package it.polimi.wcalendar.business.security.control;

import it.polimi.wcalendar.business.security.boundary.DistrictManager;
import it.polimi.wcalendar.business.security.boundary.EventManager;
import it.polimi.wcalendar.business.security.boundary.PeopleInvitedManager;
import it.polimi.wcalendar.business.security.entity.District;
import it.polimi.wcalendar.business.security.entity.Event;
import it.polimi.wcalendar.business.security.entity.Notification;
import it.polimi.wcalendar.business.security.entity.PeopleInvited;
import it.polimi.wcalendar.business.security.entity.User;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.nio.charset.Charset;
import java.time.Instant;
import java.time.LocalDate;
import java.time.Period;
import java.time.ZoneId;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.mail.MessagingException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 *
 * @author baldo
 */
public class OpenWeatherDownloader {

    DistrictManager dm = new DistrictManager();
    EventManager em = new EventManager();
    PeopleInvitedManager pim = new PeopleInvitedManager();

    private String readAll(Reader rd) throws IOException {
        StringBuilder sb = new StringBuilder();
        int cp;
        while ((cp = rd.read()) != -1) {
            sb.append((char) cp);
        }
        return sb.toString();
    }

    public JSONObject readJsonFromUrl(String url) throws IOException, JSONException {
        try (InputStream is = new URL(url).openStream()) {
            BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
            String jsonText = readAll(rd);
            JSONObject json = new JSONObject(jsonText);
            return json;
        } catch (IOException e) {
            System.out.println("IOException occurred");
        } catch (JSONException e) {
            System.out.println("JSONException occurred");

        }
        return null;
    }
//If you are a tester and you have to check this code, I just want to say I'm sorry

    public void Parse() throws IOException, JSONException {

        List districtList;
        districtList = dm.getAll();
        Iterator iterator = districtList.iterator();
        //Iterate on all district
        while (iterator.hasNext()) {
            District district;
            district = (District) iterator.next();
            JSONObject json;
            String name = district.getName();
            double longitude = district.getLongitude();
            double latitude = district.getLatitude();
            // String url = this.createURLCoordinates(latitude, longitude, 16);
            String url = this.createURLName(name, 16);
            System.out.println(url);
            json = readJsonFromUrl(url);
            if (json != null) {
                JSONArray jsonArray;
                jsonArray = json.optJSONArray("list");
                if (jsonArray != null) {
                    int values = jsonArray.length();
                    JSONObject weather = jsonArray.getJSONObject(3).optJSONArray("weather").optJSONObject(0);
                    if (weather != null) {
                        int weatherID = weather.getInt("id");
                        //Check the weather of the district, with some magic (See openweather api)   
                        if (CheckWeather(weatherID)) {
                            java.util.Date time = new java.util.Date(jsonArray.optJSONObject(3).optLong("dt") * 1000);
                            LocalDate data = Instant.ofEpochMilli(time.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();
                            JSONObject obj = jsonArray.getJSONObject(4);
                            String status = obj.getJSONArray("weather").getJSONObject(0).getString("main");
                            List eventList;

                            eventList = em.getByDistrict(district);
                            Iterator iterator2 = eventList.iterator();
                            while (iterator2.hasNext()) {

                                Event event;
                                event = (Event) iterator2.next();
                                //Check if the event is inside or outside
                                if (event.getInOut()) {
                                    Date input = event.getData();
                                    LocalDate data1 = Instant.ofEpochMilli(input.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();
                                    Date input2 = event.getData_end();
                                    LocalDate data2 = Instant.ofEpochMilli(input2.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();
                                    //Chck if the event is interested by the bad weather
                                    if (data1.equals(data) || data2.equals(data) || (data1.isBefore(data) && data2.isAfter(data))) {
                                        User creator = event.getCreator();
                                        Date firstDate = checkOtherDays(jsonArray, data1, data2);
                                        SendOwnerMail(creator, data1, data2, firstDate);
                                        List invitedList;
                                        invitedList = pim.GetByEvent(event);
                                        Iterator iterator3 = invitedList.iterator();
                                        //take all the people invited and send a mail to them
                                        while (iterator3.hasNext()) {
                                            PeopleInvited people = (PeopleInvited) iterator3.next();
                                            if (people.getAnswer().equalsIgnoreCase("yes")) {
                                                User user = people.getUser();
                                                SendUserMail(user, data1, data2);
                                                System.out.println(user.toString());
                                            }
                                        }
                                    }

                                }
                                System.out.println(data);
                                System.out.println(name);
                                System.out.println(status);
                            }
                        } else {
                            System.out.println("What a beautiful sky");
                        }
                    } else {
                        System.out.println("Can't find weather");
                    }
                } else {
                    System.out.println("There is a problem with the list");
                }
            } else {
                System.out.println("Something is wrong with this city");
            }
        }
    }

    /**
     * rl
     *
     * @param latitude
     * @param longitude
     * @param count
     * @return
     */
    public String createURLCoordinates(Double latitude, Double longitude, int count) {

        return "http://api.openweathermap.org/data/2.5/forecast/daily?" + "lat=" + latitude + "&lon=" + longitude + "&cnt=" + count + "&mode=json";
    }

    public String createURLName(String name, int count) {
        return "http://api.openweathermap.org/data/2.5/forecast/daily?" + "q=" + name + "&cnt=" + count + "&mode=json";

    }

    /**
     *
     * @param id
     * @return
     */
    public boolean CheckWeather(int id) {
        //It's a kind of Magic
        if ((id >= 800 && id < 805) || (id > 950 && id < 957)) {
            return false;
        }

        return true;

    }

    public java.util.Date checkOtherDays(JSONArray jsonArray, LocalDate date, LocalDate date_end) {
        boolean firstDay = true;
        Date time = null;

        long days = Period.between(date, date_end).getDays() + 1;
        long years = Period.between(date, date_end).getYears();
        long months = Period.between(date, date_end).getMonths();
        if (years != 0 || months != 0) {
            return null;
        }
        long counter = 0;
        try {
            for (int i = 4; i < 16 || counter == days; i++) {
                if (CheckWeather(jsonArray.getJSONObject(i).getJSONArray("weather").getJSONObject(0).getInt("id"))) {
                    counter = 0;
                    firstDay = true;
                    time = null;
                } else {
                    if (firstDay) {
                        firstDay = false;
                        time = new java.util.Date(jsonArray.getJSONObject(i).getLong("dt") * 1000);
                    }
                    counter++;
                }
            }
            return time;
        } catch (JSONException ex) {
            Logger.getLogger(OpenWeatherDownloader.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;

    }

    private void SendUserMail(User user, LocalDate data1, LocalDate data2) {
        try {
            Notification.sendMail(user.getEmail(), "Advise@WCalendar.it", "Bad Weather Advise", "WCalendar informs you that during the event starting: " + data1.toString() + "and ending: " + data2.toString() + "there is a chance of bad weather");
        } catch (MessagingException ex) {
            Logger.getLogger(OpenWeatherDownloader.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void SendOwnerMail(User creator, LocalDate data1, LocalDate data2, Date firstDate) {
        try {
            if (firstDate != null) {
                Notification.sendMail(creator.getEmail(),
                        "Advise@WCalendar.it",
                        "Bad Weather Advise",
                        "WCalendar informs you that during your event starting: "
                        + data1.toString() + "and ending: " + data2.toString()
                        + "there is a chance of bad weather,but you can move the event starting from: "
                        + firstDate.toString());
            } else {
                Notification.sendMail(creator.getEmail(),
                        "Advise@WCalendar.it",
                        "Bad Weather Advise",
                        "WCalendar informs you that during your event starting: "
                        + data1.toString() + "and ending: " + data2.toString()
                        + "there is a chance of bad weather");
            }
        } catch (MessagingException ex) {
            Logger.getLogger(OpenWeatherDownloader.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
